#pragma once

#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <strings.h>
#include "task.hpp"
#include "threadPool.hpp"

using namespace std;

enum errornum
{
    SOCK_FAILED = 1,
    BIND_FAILED,
    LISTEN_FAILED,
    ACCEPT_FAILED
};

class tcpserver
{
public:
    // 构造
    tcpserver(uint16_t serverport)
        : _serverport(serverport), _listensock(-1)
    {
        // 1、创建套接字
        _listensock = socket(AF_INET, SOCK_STREAM, 0);
        if (_listensock == -1) // 套接字创建失败
        {
            cerr << "套接字创建失败" << endl;
            exit(SOCK_FAILED);
        }

        cout << "创建套接字成功，sock:" << _listensock << endl;

        // 2、绑定套接字
        // 2.1 构建服务器属性结构
        struct sockaddr_in serverinfor; // 服务器信息
        bzero(&serverinfor, sizeof(serverinfor));
        serverinfor.sin_family = AF_INET;
        serverinfor.sin_addr.s_addr = htonl(INADDR_ANY);
        serverinfor.sin_port = htons(_serverport);
        // 2.2绑定套接字
        int n = bind(_listensock, (struct sockaddr *)&serverinfor, sizeof(serverinfor));
        if (n < 0)
        {
            cerr << "套接字绑定失败" << endl;
            exit(BIND_FAILED);
        }

        cout << "绑定套接字成功" << endl;

        // 3、设置套接字为监听状态
        n = listen(_listensock, 5);
        if (n < 0)
        {
            cerr << "设置套接字监听状态失败" << endl;
            exit(LISTEN_FAILED);
        }

        cout << "设置套接字为监听状态成功" << endl;
    }

    // 启动
    void start()
    {
        while (true)
        {
            // 1、构建客户端属性结构
            struct sockaddr_in clientinfor; // 服务器信息
            socklen_t len = sizeof(clientinfor);
            bzero(&clientinfor, sizeof(clientinfor));

            // 2、获取链接
            int sock = accept(_listensock, (struct sockaddr *)&(clientinfor), &len);
            if (sock < 0)
            {
                cerr << "获取链接失败" << endl;
                exit(ACCEPT_FAILED);
            }

            cout << "获取链接成功，sock:" << sock << endl;

            // 3、构建IO任务，并交由线程池处理
            threadPool<task>::getinstance()->push(task(sock, clientinfor, serverIO));
        }
    }

    // 删除拷贝构造
    tcpserver(const tcpserver &) = delete;

    // 删除赋值重载
    tcpserver &operator=(const tcpserver &) = delete;

    // 析构
    ~tcpserver()
    {
        close(_listensock); // 关闭文件
    }

private:
    int _listensock;      // 监听端口号
    uint16_t _serverport; // 服务器端口号
};